TypeScript μ νΈλ¦¬ν° νμ μ κ°λ ₯ν κΈ°λ₯μ νμ©νμ¬ λ κΉλνκ³ μ μ§λ³΄μνκΈ° μ¬μ°λ©° νμ μμ ν μ½λλ₯Ό μμ±νμΈμ. μ μΈκ³ κ°λ°μλ₯Ό μν μ€μ μ¬λ‘μ ν¨κ» μ€μ©μ μΈ μ ν리μΌμ΄μ μ νμν΄ λ³΄μΈμ.
TypeScript μ νΈλ¦¬ν° νμ λ§μ€ν°νκΈ°: κΈλ‘λ² κ°λ°μλ₯Ό μν μ€μ© κ°μ΄λ
TypeScriptλ μ½λμ νμ μμ μ±, κ°λ μ±, μ μ§λ³΄μμ±μ ν¬κ² ν₯μμν¬ μ μλ κ°λ ₯ν λ΄μ₯ μ νΈλ¦¬ν° νμ μΈνΈλ₯Ό μ 곡ν©λλ€. μ΄ μ νΈλ¦¬ν° νμ λ€μ λ³Έμ§μ μΌλ‘ κΈ°μ‘΄ νμ μ μ μ©ν μ μλ 미리 μ μλ νμ λ³νμ΄λ©°, λ°λ³΅μ μ΄κ³ μ€λ₯κ° λ°μνκΈ° μ¬μ΄ μ½λλ₯Ό μμ±νλ μκ³ λ₯Ό λμ΄μ€λλ€. μ΄ κ°μ΄λλ μ μΈκ³ κ°λ°μλ€μκ² κ³΅κ°μ μ»μ μ μλ μ€μ μ μΈ μμμ ν¨κ» λ€μν μ νΈλ¦¬ν° νμ μ νꡬν κ²μ λλ€.
μ νΈλ¦¬ν° νμ μ μ¬μ©νλ μ΄μ ?
μ νΈλ¦¬ν° νμ μ μΌλ°μ μΈ νμ μ‘°μ μλ리μ€λ₯Ό ν΄κ²°ν©λλ€. μ΄λ₯Ό νμ©νμ¬ λ€μμ μνν μ μμ΅λλ€:
- μμ©κ΅¬ μ½λ κ°μ: λ°λ³΅μ μΈ νμ μ μ μμ±μ νΌνμΈμ.
- νμ μμ μ± ν₯μ: μ½λκ° νμ μ μ½μ μ€μνλμ§ νμΈνμΈμ.
- μ½λ κ°λ μ± ν₯μ: νμ μ μλ₯Ό λ κ°κ²°νκ³ μ΄ν΄νκΈ° μ½κ² λ§λμΈμ.
- μ μ§λ³΄μμ± μ¦λ: μμ μ λ¨μννκ³ μ€λ₯ λ°μ μνμ μ€μ΄μΈμ.
ν΅μ¬ μ νΈλ¦¬ν° νμ
Partial<T>
Partial<T>λ Tμ λͺ¨λ μμ±μ΄ μ ν μ¬νμΌλ‘ μ€μ λ νμ
μ ꡬμ±ν©λλ€. μ΄λ λΆλΆ μ
λ°μ΄νΈ λλ κ΅¬μ± κ°μ²΄λ₯Ό μν νμ
μ μμ±ν λ νΉν μ μ©ν©λλ€.
μμ:
λ€μν μ§μμ κ³ κ°μ λμμΌλ‘ νλ μ μμκ±°λ νλ«νΌμ ꡬμΆνλ€κ³ μμν΄ λ³΄μΈμ. Customer νμ
μ λ€μκ³Ό κ°μ΅λλ€:
interface Customer {
id: string;
firstName: string;
lastName: string;
email: string;
phoneNumber: string;
address: {
street: string;
city: string;
country: string;
postalCode: string;
};
preferences?: {
language: string;
currency: string;
}
}
κ³ κ° μ 보λ₯Ό μ
λ°μ΄νΈν λ λͺ¨λ νλλ₯Ό νμλ‘ μ§μ νκ³ μΆμ§ μμ μ μμ΅λλ€. Partial<Customer>λ₯Ό μ¬μ©νλ©΄ Customerμ λͺ¨λ μμ±μ΄ μ ν μ¬νμΈ νμ
μ μ μν μ μμ΅λλ€:
type PartialCustomer = Partial<Customer>;
function updateCustomer(id: string, updates: PartialCustomer): void {
// ... implementation to update the customer with the given ID
}
updateCustomer("123", { firstName: "John", lastName: "Doe" }); // Valid
updateCustomer("456", { address: { city: "London" } }); // Valid
Readonly<T>
Readonly<T>λ Tμ λͺ¨λ μμ±μ΄ readonlyλ‘ μ€μ λμ΄ μ΄κΈ°ν ν μμ ν μ μλλ‘ νλ νμ
μ ꡬμ±ν©λλ€. μ΄λ λΆλ³μ±μ 보μ₯νλ λ° μ μ©ν©λλ€.
μμ:
μ μ μ ν리μΌμ΄μ μ κ΅¬μ± κ°μ²΄λ₯Ό μκ°ν΄ 보μΈμ:
interface AppConfig {
apiUrl: string;
theme: string;
supportedLanguages: string[];
version: string; // Added version
}
const config: AppConfig = {
apiUrl: "https://api.example.com",
theme: "dark",
supportedLanguages: ["en", "fr", "de", "es", "zh"],
version: "1.0.0"
};
μ΄κΈ°ν ν ꡬμ±μ΄ μ€μλ‘ μμ λλ κ²μ λ°©μ§νλ €λ©΄ Readonly<AppConfig>λ₯Ό μ¬μ©ν μ μμ΅λλ€:
type ReadonlyAppConfig = Readonly<AppConfig>;
const readonlyConfig: ReadonlyAppConfig = {
apiUrl: "https://api.example.com",
theme: "dark",
supportedLanguages: ["en", "fr", "de", "es", "zh"],
version: "1.0.0"
};
// readonlyConfig.apiUrl = "https://newapi.example.com"; // Error: Cannot assign to 'apiUrl' because it is a read-only property.
Pick<T, K>
Pick<T, K>λ Tμμ μμ± μ§ν© Kλ₯Ό μ ννμ¬ νμ
μ ꡬμ±ν©λλ€. μ¬κΈ°μ Kλ ν¬ν¨νλ €λ μμ± μ΄λ¦μ λνλ΄λ λ¬Έμμ΄ λ¦¬ν°λ΄ νμ
μ μ λμ¨μ
λλ€.
μμ:
λ€μν μμ±μ κ°μ§ Event μΈν°νμ΄μ€κ° μλ€κ³ κ°μ ν΄ λ΄
μλ€:
interface Event {
id: string;
title: string;
description: string;
location: string;
startTime: Date;
endTime: Date;
organizer: string;
attendees: string[];
}
νΉμ νμ κ΅¬μ± μμμ λν΄ title, location, startTimeλ§ νμν κ²½μ° Pickμ μ¬μ©ν μ μμ΅λλ€:
type EventSummary = Pick<Event, "title" | "location" | "startTime">;
function displayEventSummary(event: EventSummary): void {
console.log(`Event: ${event.title} at ${event.location} on ${event.startTime}`);
}
Omit<T, K>
Omit<T, K>λ Tμμ μμ± μ§ν© Kλ₯Ό μ μΈνμ¬ νμ
μ ꡬμ±ν©λλ€. μ¬κΈ°μ Kλ μ μΈνλ €λ μμ± μ΄λ¦μ λνλ΄λ λ¬Έμμ΄ λ¦¬ν°λ΄ νμ
μ μ λμ¨μ
λλ€. μ΄λ Pickμ λ°λμ
λλ€.
μμ:
λμΌν Event μΈν°νμ΄μ€λ₯Ό μ¬μ©νμ¬ μ μ΄λ²€νΈλ₯Ό μμ±νκΈ° μν νμ
μ λ§λ€λ €λ©΄ μΌλ°μ μΌλ‘ λ°±μλμμ μμ±λλ id μμ±μ μ μΈν μ μμ΅λλ€:
type NewEvent = Omit<Event, "id">;
function createEvent(event: NewEvent): void {
// ... implementation to create a new event
}
Record<K, T>
Record<K, T>λ μμ± ν€κ° Kμ΄κ³ μμ± κ°μ΄ TμΈ κ°μ²΄ νμ
μ ꡬμ±ν©λλ€. Kλ λ¬Έμμ΄ λ¦¬ν°λ΄ νμ
, μ«μ 리ν°λ΄ νμ
λλ μ¬λ³Όμ μ λμ¨μΌ μ μμ΅λλ€. μ΄λ μ¬μ λλ λ§΅μ μμ±νλ λ° μ ν©ν©λλ€.
μμ:
μ ν리μΌμ΄μ
μ μ¬μ©μ μΈν°νμ΄μ€μ λν λ²μμ μ μ₯ν΄μΌ νλ€κ³ μμν΄ λ³΄μΈμ. Recordλ₯Ό μ¬μ©νμ¬ λ²μμ μν νμ
μ μ μν μ μμ΅λλ€:
type Translations = Record<string, string>;
const enTranslations: Translations = {
"hello": "Hello",
"goodbye": "Goodbye",
"welcome": "Welcome to our platform!"
};
const frTranslations: Translations = {
"hello": "Bonjour",
"goodbye": "Au revoir",
"welcome": "Bienvenue sur notre plateforme !"
};
function translate(key: string, language: string): string {
const translations = language === "en" ? enTranslations : frTranslations; //Simplified
return translations[key] || key; // Fallback to the key if no translation is found
}
console.log(translate("hello", "en")); // Output: Hello
console.log(translate("hello", "fr")); // Output: Bonjour
console.log(translate("nonexistent", "en")); // Output: nonexistent
Exclude<T, U>
Exclude<T, U>λ Tμμ Uμ ν λΉ κ°λ₯ν λͺ¨λ μ λμ¨ λ©€λ²λ₯Ό μ μΈνμ¬ νμ
μ ꡬμ±ν©λλ€. μ΄λ μ λμ¨μμ νΉμ νμ
μ νν°λ§νλ λ° μ μ©ν©λλ€.
μμ:
λ€μν μ΄λ²€νΈ μ νμ λνλ΄λ νμ μ΄ μμ μ μμ΅λλ€:
type EventType = "concert" | "conference" | "workshop" | "webinar";
"webinar" μ΄λ²€νΈλ₯Ό μ μΈνλ νμ
μ λ§λ€λ €λ©΄ Excludeλ₯Ό μ¬μ©ν μ μμ΅λλ€:
type PhysicalEvent = Exclude<EventType, "webinar">;
// PhysicalEvent is now "concert" | "conference" | "workshop"
function attendPhysicalEvent(event: PhysicalEvent): void {
console.log(`Attending a ${event}`);
}
// attendPhysicalEvent("webinar"); // Error: Argument of type '"webinar"' is not assignable to parameter of type '"concert" | "conference" | "workshop"'.
attendPhysicalEvent("concert"); // Valid
Extract<T, U>
Extract<T, U>λ Tμμ Uμ ν λΉ κ°λ₯ν λͺ¨λ μ λμ¨ λ©€λ²λ₯Ό μΆμΆνμ¬ νμ
μ ꡬμ±ν©λλ€. μ΄λ Excludeμ λ°λμ
λλ€.
μμ:
λμΌν EventTypeμ μ¬μ©νμ¬ μ¨λΉλ μ΄λ²€νΈ νμ
μ μΆμΆν μ μμ΅λλ€:
type OnlineEvent = Extract<EventType, "webinar">;
// OnlineEvent is now "webinar"
function attendOnlineEvent(event: OnlineEvent): void {
console.log(`Attending a ${event} online`);
}
attendOnlineEvent("webinar"); // Valid
// attendOnlineEvent("concert"); // Error: Argument of type '"concert"' is not assignable to parameter of type '"webinar"'.
NonNullable<T>
NonNullable<T>λ Tμμ nullκ³Ό undefinedλ₯Ό μ μΈνμ¬ νμ
μ ꡬμ±ν©λλ€.
μμ:
type MaybeString = string | null | undefined;
type DefinitelyString = NonNullable<MaybeString>;
// DefinitelyString is now string
function processString(str: DefinitelyString): void {
console.log(str.toUpperCase());
}
// processString(null); // Error: Argument of type 'null' is not assignable to parameter of type 'string'.
// processString(undefined); // Error: Argument of type 'undefined' is not assignable to parameter of type 'string'.
processString("hello"); // Valid
ReturnType<T>
ReturnType<T>λ ν¨μ Tμ λ°ν νμ
μΌλ‘ ꡬμ±λ νμ
μ ꡬμ±ν©λλ€.
μμ:
function greet(name: string): string {
return `Hello, ${name}!`;
}
type Greeting = ReturnType<typeof greet>;
// Greeting is now string
const message: Greeting = greet("World");
console.log(message);
Parameters<T>
Parameters<T>λ ν¨μ νμ
Tμ λ§€κ°λ³μ νμ
μΌλ‘λΆν° νν νμ
μ ꡬμ±ν©λλ€.
μμ:
function logEvent(eventName: string, eventData: object): void {
console.log(`Event: ${eventName}`, eventData);
}
type LogEventParams = Parameters<typeof logEvent>;
// LogEventParams is now [eventName: string, eventData: object]
const params: LogEventParams = ["user_login", { userId: "123", timestamp: Date.now() }];
logEvent(...params);
ConstructorParameters<T>
ConstructorParameters<T>λ μμ±μ ν¨μ νμ
Tμ λ§€κ°λ³μ νμ
μΌλ‘λΆν° νν λλ λ°°μ΄ νμ
μ ꡬμ±ν©λλ€. μ΄λ ν΄λμ€μ μμ±μμ μ λ¬λμ΄μΌ νλ μΈμμ νμ
μ μΆλ‘ ν©λλ€.
μμ:
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
type GreeterParams = ConstructorParameters<typeof Greeter>;
// GreeterParams is now [message: string]
const paramsGreeter: GreeterParams = ["World"];
const greeterInstance = new Greeter(...paramsGreeter);
console.log(greeterInstance.greet()); // Outputs: Hello, World
Required<T>
Required<T>λ Tμ λͺ¨λ μμ±μ΄ νμλ‘ μ€μ λ νμ
μ ꡬμ±ν©λλ€. μ΄λ λͺ¨λ μ νμ μμ±μ νμλ‘ λ§λλλ€.
μμ:
interface UserProfile {
name: string;
age?: number;
email?: string;
}
type RequiredUserProfile = Required<UserProfile>;
// RequiredUserProfile is now { name: string; age: number; email: string; }
const completeProfile: RequiredUserProfile = {
name: "Alice",
age: 30,
email: "alice@example.com"
};
// const incompleteProfile: RequiredUserProfile = { name: "Bob" }; // Error: Property 'age' is missing in type '{ name: string; }' but required in type 'Required'.
κ³ κΈ μ νΈλ¦¬ν° νμ
ν νλ¦Ώ 리ν°λ΄ νμ
ν νλ¦Ώ 리ν°λ΄ νμ μ κΈ°μ‘΄ λ¬Έμμ΄ λ¦¬ν°λ΄ νμ , μ«μ 리ν°λ΄ νμ λ±μ μ°κ²°νμ¬ μλ‘μ΄ λ¬Έμμ΄ λ¦¬ν°λ΄ νμ μ ꡬμ±ν μ μλλ‘ ν©λλ€. μ΄λ κ°λ ₯ν λ¬Έμμ΄ κΈ°λ° νμ μ‘°μμ κ°λ₯νκ² ν©λλ€.
μμ:
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type APIEndpoint = `/api/users` | `/api/products`;
type RequestURL = `${HTTPMethod} ${APIEndpoint}`;
// RequestURL is now "GET /api/users" | "POST /api/users" | "PUT /api/users" | "DELETE /api/users" | "GET /api/products" | "POST /api/products" | "PUT /api/products" | "DELETE /api/products"
function makeRequest(url: RequestURL): void {
console.log(`Making request to ${url}`);
}
makeRequest("GET /api/users"); // Valid
// makeRequest("INVALID /api/users"); // Error
μ‘°κ±΄λΆ νμ
μ‘°κ±΄λΆ νμ
μ νμ
κ΄κ³λ₯Ό λνλ΄λ 쑰건μ λ°λΌ νμ
μ μ μν μ μλλ‘ ν©λλ€. infer ν€μλλ₯Ό μ¬μ©νμ¬ νμ
μ 보λ₯Ό μΆμΆν©λλ€.
μμ:
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
// If T is a Promise, then the type is U; otherwise, the type is T.
async function fetchData(): Promise<number> {
return 42;
}
type Data = UnwrapPromise<ReturnType<typeof fetchData>>;
// Data is now number
function processData(data: Data): void {
console.log(data * 2);
}
processData(await fetchData());
μ€μ©μ μΈ μ ν리μΌμ΄μ λ° μ€μ μλ리μ€
μ νΈλ¦¬ν° νμ μ΄ λΉμ λ°νλ λ 볡μ‘ν μ€μ μλ리μ€λ₯Ό μ΄ν΄λ³΄κ² μ΅λλ€.
1. νΌ νΈλ€λ§
νΌμ λ€λ£° λ, μ΄κΈ° νΌ κ°, μ λ°μ΄νΈλ νΌ κ°, μ΅μ’ μ μΆλ κ°μ λνλ΄μΌ νλ μλ리μ€κ° μμ£Ό λ°μν©λλ€. μ νΈλ¦¬ν° νμ μ μ΄λ¬ν λ€μν μνλ₯Ό ν¨μ¨μ μΌλ‘ κ΄λ¦¬νλ λ° λμμ΄ λ μ μμ΅λλ€.
interface FormData {
firstName: string;
lastName: string;
email: string;
country: string; // Required
city?: string; // Optional
postalCode?: string;
newsletterSubscription?: boolean;
}
// Initial form values (optional fields)
type InitialFormValues = Partial<FormData>;
// Updated form values (some fields might be missing)
type UpdatedFormValues = Partial<FormData>;
// Required fields for submission
type RequiredForSubmission = Required<Pick<FormData, 'firstName' | 'lastName' | 'email' | 'country'>>;
// Use these types in your form components
function initializeForm(initialValues: InitialFormValues): void { }
function updateForm(updates: UpdatedFormValues): void {}
function submitForm(data: RequiredForSubmission): void {}
const initialForm: InitialFormValues = { newsletterSubscription: true };
const updateFormValues: UpdatedFormValues = {
firstName: "John",
lastName: "Doe"
};
// const submissionData: RequiredForSubmission = { firstName: "test", lastName: "test", email: "test" }; // ERROR: Missing 'country'
const submissionData: RequiredForSubmission = { firstName: "test", lastName: "test", email: "test", country: "USA" }; //OK
2. API λ°μ΄ν° λ³ν
APIμμ λ°μ΄ν°λ₯Ό μλΉν λ, μ ν리μΌμ΄μ μ λ§κ² λ°μ΄ν°λ₯Ό λ€λ₯Έ νμμΌλ‘ λ³νν΄μΌ ν μ μμ΅λλ€. μ νΈλ¦¬ν° νμ μ λ³νλ λ°μ΄ν°μ ꡬ쑰λ₯Ό μ μνλ λ° λμμ΄ λ μ μμ΅λλ€.
interface APIResponse {
user_id: string;
first_name: string;
last_name: string;
email_address: string;
profile_picture_url: string;
is_active: boolean;
}
// Transform the API response to a more readable format
type UserData = {
id: string;
fullName: string;
email: string;
avatar: string;
active: boolean;
};
function transformApiResponse(response: APIResponse): UserData {
return {
id: response.user_id,
fullName: `${response.first_name} ${response.last_name}`,
email: response.email_address,
avatar: response.profile_picture_url,
active: response.is_active
};
}
function fetchAndTransformData(url: string): Promise<UserData> {
return fetch(url)
.then(response => response.json())
.then(data => transformApiResponse(data));
}
// You can even enforce the type by:
function saferTransformApiResponse(response: APIResponse): UserData {
const {user_id, first_name, last_name, email_address, profile_picture_url, is_active} = response;
const transformed: UserData = {
id: user_id,
fullName: `${first_name} ${last_name}`,
email: email_address,
avatar: profile_picture_url,
active: is_active
};
return transformed;
}
3. κ΅¬μ± κ°μ²΄ μ²λ¦¬
κ΅¬μ± κ°μ²΄λ λ§μ μ ν리μΌμ΄μ μμ νν μ¬μ©λ©λλ€. μ νΈλ¦¬ν° νμ μ κ΅¬μ± κ°μ²΄μ ꡬ쑰λ₯Ό μ μνκ³ μ¬λ°λ₯΄κ² μ¬μ©λλμ§ νμΈνλ λ° λμμ΄ λ μ μμ΅λλ€.
interface AppSettings {
theme: "light" | "dark";
language: string;
notificationsEnabled: boolean;
apiUrl?: string; // Optional API URL for different environments
timeout?: number; //Optional
}
// Default settings
const defaultSettings: AppSettings = {
theme: "light",
language: "en",
notificationsEnabled: true
};
// Function to merge user settings with default settings
function mergeSettings(userSettings: Partial<AppSettings>): AppSettings {
return { ...defaultSettings, ...userSettings };
}
// Use the merged settings in your application
const mergedSettings = mergeSettings({ theme: "dark", apiUrl: "https://customapi.example.com" });
console.log(mergedSettings);
μ νΈλ¦¬ν° νμ μ ν¨κ³Όμ μΈ μ¬μ©μ μν ν
- κ°λ¨νκ² μμνμΈμ: 볡μ‘ν μ νΈλ¦¬ν° νμ
μΌλ‘ λμ΄κ°κΈ° μ μ
Partialλ°Readonlyμ κ°μ κΈ°λ³Έ μ νΈλ¦¬ν° νμ λΆν° μμνμΈμ. - μ€λͺ μ μΈ μ΄λ¦ μ¬μ©: κ°λ μ±μ λμ΄κΈ° μν΄ νμ λ³μΉμ μλ―Έ μλ μ΄λ¦μ λΆμ¬νμΈμ.
- μ νΈλ¦¬ν° νμ κ²°ν©: μ¬λ¬ μ νΈλ¦¬ν° νμ μ κ²°ν©νμ¬ λ³΅μ‘ν νμ λ³νμ λ¬μ±ν μ μμ΅λλ€.
- νΈμ§κΈ° μ§μ νμ©: TypeScriptμ λ°μ΄λ νΈμ§κΈ° μ§μμ νμ©νμ¬ μ νΈλ¦¬ν° νμ μ ν¨κ³Όλ₯Ό νμνμΈμ.
- κΈ°λ³Έ κ°λ μ΄ν΄: μ νΈλ¦¬ν° νμ μ ν¨κ³Όμ μΌλ‘ μ¬μ©νλ €λ©΄ TypeScript νμ μμ€ν μ λν νμ€ν μ΄ν΄κ° νμμ μ λλ€.
κ²°λ‘
TypeScript μ νΈλ¦¬ν° νμ μ μ½λμ νμ§κ³Ό μ μ§λ³΄μμ±μ ν¬κ² ν₯μμν¬ μ μλ κ°λ ₯ν λꡬμ λλ€. μ΄λ¬ν μ νΈλ¦¬ν° νμ μ ν¨κ³Όμ μΌλ‘ μ΄ν΄νκ³ μ μ©ν¨μΌλ‘μ¨, κΈλ‘λ² κ°λ° νκ²½μ μꡬ μ¬νμ μΆ©μ‘±νλ λ κΉλνκ³ νμ μμ νλ©° κ²¬κ³ ν μ ν리μΌμ΄μ μ μμ±ν μ μμ΅λλ€. μ΄ κ°μ΄λλ μΌλ°μ μΈ μ νΈλ¦¬ν° νμ κ³Ό μ€μ μμμ λν ν¬κ΄μ μΈ κ°μλ₯Ό μ 곡νμ΅λλ€. μ΄λ€μ μ€ννκ³ TypeScript νλ‘μ νΈλ₯Ό ν₯μμν¬ μ μ¬λ ₯μ νμν΄ λ³΄μΈμ. μ νΈλ¦¬ν° νμ μ μ¬μ©ν λ κ°λ μ±κ³Ό λͺ νμ±μ μ°μ μνκ³ , λλ£ κ°λ°μλ€μ΄ μ΄λμ μλ νμ μ΄ν΄νκ³ μ μ§λ³΄μνκΈ° μ¬μ΄ μ½λλ₯Ό μμ±νλλ‘ λ Έλ ₯ν΄μΌ ν©λλ€.